/**
 * 
 */
package profile.aspect;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
 * @author ductrung.tran
 *
 */
public class MethodCall {

	private static final ThreadLocal<MethodCall> contextHolder = new ThreadLocal<MethodCall>() {
		@Override
		protected MethodCall initialValue() {
			return new MethodCall();
		}
	};
	
	private final long id;
	private String name;
	private long execTime;
	private String testContextId;
	
	private Map<String, Long> timeMap = new HashMap<String, Long>();
	
	private static class Counter {
		private volatile int count;
		private volatile long timestamp = System.currentTimeMillis();
		
		{
			System.out.println("new counter");
		}
		
		public synchronized void increment() {
			count++;
			System.out.println("increment " + count);
		}
		
		public synchronized void decrement() {
			count--;
			System.out.println("decrement " + count);
			if (count == 0) {
				timestamp = System.currentTimeMillis();
			}
		}
		
		public synchronized boolean noActiveContextSince(long ms) {
			return count == 0 && (System.currentTimeMillis() - timestamp) >= ms;
		}
		
	}
	
	private static Counter counter = new Counter();
	
	private MethodCall() {
		CallContext testContext = CallContextHolder.getContext();
		testContextId = testContext.getId();
		id = testContext.newStep();
		//this.id = ID.incrementAndGet();
		counter.increment();
		
	}
	
	public static MethodCall get() {
		return contextHolder.get();
	}
	
	public static long getId() {
		return get().id;
	}
	
	public static void remove() {
		contextHolder.remove();
		counter.decrement();
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public String getTestContextId() {
		return testContextId;
	}
	
	@Override
	public String toString() {
		return testContextId + ";" + id + ";" + name + ";execTime:" + execTime + ";" + toStringMap();
	}

	private String toStringMap() {
		StringBuilder builder = new StringBuilder();
		for (Entry<String, Long> entry : timeMap.entrySet()) {
			builder.append(entry.getKey()).append(':').append(entry.getValue()).append(';');
		}
		
		builder.deleteCharAt(builder.length()-1);
		
		return builder.toString();
	}

	public void setExecTime(long time) {
		this.execTime = time;
	}
	
	public long getExecTime() {
		return execTime;
	}

	public void setTime(String string, long time) {
		timeMap.put(string, time);
	}
	
	public Map<String, Long> getTimeMap() {
		return timeMap;
	}

	public static boolean noActiveContextSince(long ms) {
		return counter.noActiveContextSince(ms);
	}
}
